package com.zyx.xunyilu.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zyx.xunyilu.config.jwt.JWTUtils;
import com.zyx.xunyilu.entity.User;
import com.zyx.xunyilu.enums.RegisterStatus;
import com.zyx.xunyilu.enums.Roles;
import com.zyx.xunyilu.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;

/**
 * @ClassName: UserService
 * @author: zyx
 * @E-mail: 1377631190@qq.com
 * @DATE: 2019/11/11 19:04
 */
@Slf4j
@Service
public class UserService {

    private static final String REGISTER = "register";

    @Autowired
    UserMapper userMapper;

    @Autowired
    JWTUtils jwtUtils;

    public Integer count() {
        return userMapper.selectCount(new LambdaQueryWrapper<User>().eq(User::getRegister, RegisterStatus.IS_REGISTER));
    }

    public IPage<User> page(IPage<User> page, User user) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        if (user.getName() != null) {
            queryWrapper.like(User::getName, user.getName());
        }
        if (user.getSex() != null) {
            queryWrapper.eq(User::getSex, user.getSex());
        }
        if (user.getRegister() != null) {
            queryWrapper.eq(User::getRegister, user.getRegister());
        }
        return userMapper.selectPage(page, queryWrapper);
    }

    /**
     * 注册用户
     */
    public User register(User user) {
        String solt = this.getSolt();
        String hashPwd = this.hashPwd(user, solt);
        if (!StringUtils.isEmpty(hashPwd)) {
            user.setTime(new Date())
                .setPassword(hashPwd)
                .setRegister(RegisterStatus.NO_REGISTER)
                .setSolt(solt);
        }
        if (userMapper.insert(user) > 0) {
            return userMapper.selectOne(new QueryWrapper<User>().eq("name", user.getName()).eq("password", hashPwd));
        }
        return null;
    }

    /**
     * 用户登录
     * @param user 要登录的用户信息
     * @return  是否登录成功
     */
    public boolean login(User user) {
        if (user == null || StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getName())) {
            throw new RuntimeException("用户为空");
        }
        User name = userMapper.selectOne(new QueryWrapper<User>().eq("name", user.getName()));

        if (name == null) {
            throw new RuntimeException("当前用户不存在");
        }
        String pwd = this.hashPwd(user, name.getSolt());
        user.setPassword(pwd);
        QueryWrapper<User> login = new QueryWrapper<User>()
                .eq("name", user.getName())
                .eq("password", pwd);
        if (userMapper.selectCount(login) > 0) {
            if (userMapper.selectCount(login .eq(REGISTER, RegisterStatus.IS_REGISTER.getRegister())) > 0) {
                return true;
            }
            log.error("{} -用户尚未完成注册", user.getName());
            throw new RuntimeException("该用户尚未完成注册");
        } else {
            throw new RuntimeException("用户名或密码错误");
        }
    }

    /**
     * 验证邮箱是否可以使用（需要有限验证之后才算不可使用）
     * @param email 邮箱号码
     * @return  true 可以使用 false 不可使用
     */
    public boolean checkEmail(String email) {
        if (StringUtils.isEmpty(email)) {
            return false;
        }
        return userMapper.selectCount(new QueryWrapper<User>()
                .eq("email", email)
                .eq("register", RegisterStatus.IS_REGISTER.getRegister())) <= 0;
    }

    /**
     * 根据用户id删除用户
     * @param id  用户id
     * @return  被删除的用户
     */
    public User deleteUserById(Integer id) {
        if (id == null) {
            throw new RuntimeException("用户信息错误");
        }
        User delete = userMapper.selectById(id);
        if (delete.getAdmin().equals(Roles.ADMIN)) {
            return null;
        }
        int i = userMapper.deleteById(id);
        if (i > 0) {
            return delete;
        }
        return null;
    }

    public Integer authorize(Integer id, RegisterStatus registerStatus) {
        User user = new User().setId(id).setRegister(registerStatus);
        return userMapper.updateById(user);
    }

    /**
     * 根据用户id修改用户
     * @param user  要修改的用户
     * @return  修改后的用户信息
     */
    public User updateUserById(User user) {
        if (user.getId() == null) {
            throw new RuntimeException("用户信息错误");
        }
        if (!StringUtils.isEmpty(user.getName())) {
            User userByName = this.findUserByName(user.getName());
            if (userByName != null) {
                throw new RuntimeException("该名称已被占用");
            }
        }
        int i = userMapper.updateById(user);
        if (i > 0) {
            User result = userMapper.selectById(user.getId());
            if (!StringUtils.isEmpty(user.getName()) || !StringUtils.isEmpty(user.getPassword())) {
                String token = jwtUtils.sign(result.getName(), result.getPassword());
                result.setToken(token);
            }
            return result;
        }
        return null;
    }

    /**
     * 修改密码(需要传入token)
     * @param token 用户token
     * @param newPassword   新的密码
     * @return  产生新的token,封装成用户后返回
     * @throws RuntimeException 防止出现token无法获取到对象的问题
     */
    public User updatePassword(String token, String newPassword) throws RuntimeException {
        User user = this.findUserByToken(token);
        if (user == null) {
            throw new RuntimeException("token错误");
        }
        user.setPassword(newPassword);
        String s = this.hashPwd(user, user.getSolt());
        user.setPassword(s);
        int i = userMapper.updateById(user);
        if (i > 0) {
            User result = userMapper.selectById(user.getId());
            if (!StringUtils.isEmpty(user.getName()) || !StringUtils.isEmpty(user.getPassword())) {
                token = jwtUtils.sign(result.getName(), result.getPassword());
                result.setToken(token);
            }
            if (result == null) {
                throw new RuntimeException("更新密码失败!");
            }
            return result;
        }
        return null;
    }

    /**
     * qq绑定已经存在的用户
     * @param user  绑定的用户
     * @param openId    qq登录的唯一标识符
     */
    public User qqBindingExists(User user, String openId) {
        if (openId == null || "".equals(openId)) {
            throw new RuntimeException("openId为空");
        }
        if (this.findUserByOpenId(openId) != null) {
            throw new RuntimeException("openId已被占用!");
        }
        boolean login = this.login(user);
        if (!login) {
            log.error("openId:{}-绑定失败", openId);
            throw new RuntimeException("登录失败");
        } else {
            User result = this.findUserByName(user.getName());
            result.setOpenId(openId).setName(null);
            User user1 = this.updateUserById(result);
            if (user1 == null) {
                log.error("id:{}, openId:{}-绑定失败", user.getId(), openId);
                throw new RuntimeException("绑定失败");
            }
            return user1;
        }
    }

    /**
     * qq绑定不存在的用户,进行注册
     * @param user  待注册的用户
     * @param openId    qq登录的唯一标识符
     */
    public User qqBindingNoExists(User user, String openId) {
        if (openId == null || "".equals(openId)) {
            throw new RuntimeException("openId为空");
        }
        if (user == null || StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getName())) {
            throw new RuntimeException("用户信息错误");
        }
        User userByName = this.findUserByName(user.getName());
        if (userByName != null) {
            throw new RuntimeException("用户名已被占用!");
        }
        if (this.findUserByOpenId(openId) != null) {
            throw new RuntimeException("openId已被占用!");
        }
        if (this.findUserByEmail(user.getEmail()) != null) {
            throw new RuntimeException("email已被占用!");
        }

        user.setOpenId(openId);
        user.setRegister(RegisterStatus.IS_REGISTER);
        String solt = this.getSolt();
        String hashPwd = this.hashPwd(user, solt);
        if (!StringUtils.isEmpty(hashPwd)) {
            user.setTime(new Date())
                    .setPassword(hashPwd)
                    .setSolt(solt);
        }
        int i = userMapper.insert(user);
        if (i <= 0) {
            log.error("user:{}, openId:{}-注册失败", user, openId);
            throw new RuntimeException("注册失败");
        }
        User result = userMapper.selectOne(new QueryWrapper<User>().eq("name", user.getName()).eq("password", hashPwd));
        String token = jwtUtils.sign(result.getName(), result.getPassword());
        result.setToken(token);
        return result;
    }

    /**
     * 检查当前openId是否绑定过
     * @param openId    传入openIdd
     * @return  如果绑定过返回true 未绑定返回false
     */
    public boolean qqLoginCheck(String openId) {
        if (!StringUtils.isEmpty(openId)) {
            throw new RuntimeException("用户为空");
        }
        return this.findUserByOpenId(openId) != null;
    }

    /**
     * 通过用户token获取用户信息
     * @param token token
     */
    public User findUserByToken(String token) {
        String username = jwtUtils.getUsername(token);
        return this.findUserByName(username);
    }

    /**
     * 通过邮箱找到用户
     * @param email 查询的邮箱
     */
    public User findUserByEmail(String email) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("email", email));
    }

    /**
     * 根据openId返回用户
     * @param openId    qq唯一标识符
     * @return  返回用户
     */
    public User findUserByOpenId(String openId) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("open_id", openId));
    }

    /**
     * 根据用户名返回用户
     * @param name  用户名
     * @return  返回用户对象
     */
    public User findUserByName(String name) {
        return userMapper.selectOne(new QueryWrapper<User>().eq("name", name));
    }

    /**
     * 根据id找用户
     * @param id    用户id
     * @return  返回用户对象
     */
    public User findUserById(Integer id) {
        return userMapper.selectById(id);
    }

    /**
     * 对用户进行md5加密
     */
    private String hashPwd(User user, String solt) {
        try {
            Md5Hash hash = new Md5Hash(user.getPassword(), solt, 21);
            return hash.toHex();
        } catch (Exception e) {
            log.error("Hash加密失败! name: {}, passwrod: {}", user.getName(), user.getPassword());;
            return "";
        }
    }

    /**
     * 获取随机盐
     * @return  盐值
     */
    private String getSolt() {
        return new SecureRandomNumberGenerator().nextBytes(6).toHex();
    }
}
